package org.codefinger.dao;

import java.sql.Connection;
import java.sql.DatabaseMetaData;
import java.sql.SQLException;
import java.util.Map;

import javax.sql.DataSource;

import org.codefinger.dao.impl.DataAccesser;
import org.codefinger.dao.impl.mssql.SQLServerDataAccesser;
import org.codefinger.dao.impl.mysql.MySQLDataAccesser;
import org.codefinger.dao.impl.oracle.OracleDataAccesser;
import org.codefinger.dao.util.AbstractCache.ValueBuilder;
import org.codefinger.dao.util.ArrayIterator;
import org.codefinger.dao.util.EqualsCache;
import org.codefinger.dao.util.Lang;
import org.codefinger.dao.util.jdbc.JDBCUtil;

public class DaoUtil {

	private DataAccesser				dataAccesser;

	private EqualsCache<String, Query>	queryMap;

	public Query createQuery(String sql) {
		return queryMap.get(sql);
	}

	public Map<String, Object> getByID(String table, long id) {
		return dataAccesser.getByID(table, id);
	}

	public <T> T getByID(String table, Class<T> clas, long id) {
		return dataAccesser.getByID(table, clas, id);
	}

	public boolean deleteByID(String table, long id) {
		return dataAccesser.deleteByID(table.toUpperCase(), id);
	}

	public void deleteByID(String table, Iterable<Long> idList) {
		dataAccesser.deleteByID(table.toUpperCase(), idList);
	}

	public void deleteByID(String table, long... idArray) {
		dataAccesser.deleteByID(table.toUpperCase(), idArray);
	}

	public DeleteFrom deleteFrom(String table) {
		return new DeleteFrom(dataAccesser, table);
	}

	public boolean update(String table, Object pojo) {
		return dataAccesser.update(table.toUpperCase(), pojo);
	}

	public <T> void update(String table, Iterable<T> pojos) {
		dataAccesser.update(table.toUpperCase(), pojos.iterator());
	}

	public <T> void update(String table, T[] pojos) {
		dataAccesser.update(table.toUpperCase(), new ArrayIterator<T>(pojos));
	}

	public UpdateFrom updateFrom(String table) {
		return new UpdateFrom(dataAccesser, table);
	}

	public boolean insert(String table, Object pojo) {
		return dataAccesser.insert(table.toUpperCase(), pojo);
	}

	public <T> void insert(String table, Iterable<T> pojos) {
		dataAccesser.insert(table.toUpperCase(), pojos.iterator());
	}

	public <T> void insert(String table, T[] pojos) {
		dataAccesser.insert(table.toUpperCase(), new ArrayIterator<T>(pojos));
	}

	public InsertInto insertInto(String table) {
		return new InsertInto(dataAccesser, table);
	}

	public void setDataSource(DataSource dataSource) {
		Connection connection = null;
		try {
			connection = dataSource.getConnection();
			DatabaseMetaData databaseMetaData = connection.getMetaData();
			String name = databaseMetaData.getDatabaseProductName();
			if (name.indexOf("MySQL") > -1) {
				dataAccesser = new MySQLDataAccesser(dataSource);
			} else if (name.indexOf("Oracle") > -1) {
				dataAccesser = new OracleDataAccesser(dataSource);
			} else if (name.indexOf("Microsoft SQL Server") > -1) {
				dataAccesser = new SQLServerDataAccesser(dataSource);
			} else {
				throw Lang.makeThrow("Unknow database '%s'.", name);
			}
			queryMap = new EqualsCache<String, Query>(2048, new QueryBuilder(dataAccesser));
		} catch (SQLException e) {
			throw Lang.wrapThrow(e, "Init DBService error!");
		} finally {
			JDBCUtil.freeResource(connection, null, null);
		}
	}

	private static class QueryBuilder implements ValueBuilder<String, Query> {

		private DataAccesser	dataAccesser;

		public QueryBuilder(DataAccesser dataAccesser) {
			super();
			this.dataAccesser = dataAccesser;
		}

		@Override
		public Query build(String sql) {
			return new Query(dataAccesser.createQuerier(sql));
		}

	}

}
